package com.misboot.document.filter;

import cn.ewsd.common.bean.Audience;
import cn.ewsd.common.bean.LoginInfo;
import cn.ewsd.common.bean.UserInfo;
import cn.ewsd.common.utils.CookieUtil;
import cn.ewsd.common.utils.JwtUtil;
import cn.ewsd.common.utils.StringUtils;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.misboot.document.filter.loginInfo.LoginInfoVo;
import com.misboot.document.filter.loginInfo.UserInfoVo;
import com.misboot.document.utils.DefaultSkipUrl;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @MethodName
 * @Description   针对document权限拦截
 * 注意
 * 1.请求地址后携带.api默认放开拦截(例如: @PostMapping("/getDisableDaysInfo.api" ))
 * 2.如果放开js/css/或请求地址不携带.api等文件则在 utils ---> DefaultSkipUrl 中增加 DEFAULT_SKIP_URL.add("/v2/api-docs");
 * 3.放开接口地址时需要在gateway(/system/v2/api-docs)项目以及接口所在项目(/v2/api-docs)同时放开
 * @Author 湖南佐佑时代科技有限公司<service@zuoyo.com>
 * @Date 2020-11-6 10:28
 */
public class JwtFilter extends OncePerRequestFilter {

    static Logger logger = LoggerFactory.getLogger(JwtFilter.class);

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    // jwt相关配置
    @Autowired
    private Audience audience;

    public JwtFilter() {
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String var4 = request.getRequestURI();
        if (var4.contains(".api") || var4.contains("v1") || var4.contains("js") || var4.contains("css") || var4.contains("/actuator")) {
            logger.info("请求地址：" + var4 + " 放开拦截");
            UserInfo var10 = new UserInfo();
            LoginInfo.add(var10);
            filterChain.doFilter(request, response);
        } else {
            String var5 = request.getHeader("requestType");
            var5 = var5 == null ? "" : var5;
            //TODO 不需要认证的请求地址
            if (!isSkip(var4)) {
                String var7 = getToken(request);
                if (var5.equals("feign") && StringUtils.isNullOrEmpty(var7)) {
                    filterChain.doFilter(request, response);
                } else {

                    if (StringUtils.isNullOrEmpty(var7)) {
                        logger.info("请求地址：" + var4 + " 没有携带token");
                    }
                    String var8 = "bearer;" + var7;
                    if ("OPTIONS".equals(request.getMethod())) {
                        response.setStatus(200);
                        filterChain.doFilter(request, response);
                    } else {
                        if (!var8.startsWith("bearer;")) {
                            logger.error("token does not start with bearer;！");
                        }
                        try {
                            if (this.audience == null) {
                                WebApplicationContext var9 = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
                                this.audience = (Audience) var9.getBean("audience");
                            }

                            Claims var12 = JwtUtil.parseJWT(var7, this.audience.getBase64Secret());
                            if (var12 == null) {
                                logger.error("token解析用户数据出现问题,请检查签名是否为空");
                            }

                            request.setAttribute("claims", var12);
                            UserInfo var10 = new UserInfo();
                            var10.setUuid(Convert.toStr(var12.get("uuid")));
                            var10.setUserNameId(Convert.toStr(var12.get("userNameId")));
                            var10.setUserName(Convert.toStr(var12.get("userName")));
                            var10.setRoleId(Convert.toStr(var12.get("roleId")));
                            var10.setOrgId(Convert.toStr(var12.get("orgId")));
                            LoginInfo.add(var10);
                            //为了支持多租户重写UserInfo LoginInfo
                            UserInfoVo var11 = new UserInfoVo();
                            var11.setTenantUuid(null != var12.get("tenantUuid")
                                    ? Convert.toStr(var12.get("tenantUuid"))
                                    : null);
                            LoginInfoVo.add(var11);
                            filterChain.doFilter(request, response);
                        } catch (Exception var11) {
                            logger.error("token解析用户数据出现问题{}" + var11.getMessage());
                        }
                    }
                }
            } else {
                logger.info("请求地址：" + var4 + " 没有携带token");
                UserInfo var10 = new UserInfo();
                LoginInfo.add(var10);
                filterChain.doFilter(request, response);
            }
        }
    }


    //获取Token
    private String getToken(HttpServletRequest request) {
        String var7 = CookieUtil.getCookieByName(request, "token");
        String paramToken = request.getParameter("token");
        if (!StringUtils.isNullOrEmpty(paramToken)) {
            var7 = paramToken;
        }
        if (StringUtils.isNullOrEmpty(var7)) {
            var7 = request.getHeader("token");
        }

        try {
            // TODO 特殊处理 swagger模块token问题
            if (request.getRequestURI().contains("api-doc")) {
                Enumeration<String> enumeration = request.getHeaders("Referer");
                if (null != enumeration) {
                    if (StringUtils.isNullOrEmpty(var7) && request.getHeaders("Referer").nextElement().contains("swagger")) {
                        var7 = getParamByUrl(request.getHeaders("Referer").nextElement());
                    }
                }
            }
        }catch (Exception e){
            var7 = StrUtil.isBlank(var7) ? null : var7;
        }
        return var7;
    }


    //获取指定url中的某个参数
    public static String getParamByUrl(String url) {
        String regEx = "(\\?|&+)(.+?)=([^&]*)";//匹配参数名和参数值的正则表达式
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(url.toString());
        Map<String, String> paramMap = new LinkedHashMap<String, String>();
        while (m.find()) {
            String paramName = m.group(2);//获取参数名
            String paramVal = m.group(3);//获取参数值
            paramMap.put(paramName, paramVal);
        }
        return paramMap.get("token");
    }

    //匹配默认跳过请求地址
    private boolean isSkip(String path) {
        return DefaultSkipUrl.getDefaultSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
    }
}
